#ifndef COLLECTIONNODE_H_INCLUDED
#define COLLECTIONNODE_H_INCLUDED

//predecl
namespace cvRenderInterface { class Renderable; };

//includes
#include "DrawlistNode.h"
#include "Renderinglayer.h"
#include "Renderable.h"
#include "cvRenderlist.h"

namespace cvRenderInterface
{
	/**
	 *	@class CollectionNode.
	 *	@brief collections are specialzed renderers that draw a collections of single primitive type
	 *	very effectivly. Collections accelerate the rendering by packing invidual nodes into continous buffers
	 *	on GPU memory. Collections also make possible to draw  primitives in a batch without using actual nodes or
	 *	game objects.
	 */
	class CollectionNode : public DrawlistNode
	{
		public:
			/// create read-write collection.
			// Primitive behaves like an object and it presits
			//static CollectionNode * create(); // <must be defined by derived.>
			/// create write-once collection.
			// Primitives are continously writed/streamed in, but never drawn twice
			// or read. write-once collection's can't be sorted automatically.
			//static CollectionNode * createSingleshot();
			/// return write-target which defines an primitive in write-once collection.
			virtual Renderable * writeRenderable() =0;

			virtual void destroy() = 0;

			/// Drawing order #3

			/// Enable/disable automatic sorting for this CollectionNode
			// when sorting is enabled Collection sorts nodes into exact draworder as specified.
			// when sorting is disabled nodes are drawn in order where they are created in Collection, which is pure randomness.
			// NOTE: sorting big collections is very CPU and memory intensive task. Avoid it much as possible.
			virtual void enableSort(bool state) =0;

			/// Sort the collection node internaly.
			/// @return true if sorting operation put the collection into bits and some nodes
			/// were inserted back to mainrenderinglist.
			// pre-condition: mainlist have to be sorted.
			virtual bool sort();

			/// Average drawpriority of the collection node.
			virtual float drawPriority() const;

			/// Lower drawpriority bound.
			// If CollectionNode is the first node on the main rendering list, there is no bound.
			// if there is other node(s) before this, the bound is the previous node's higherBound or m_draworder+MIN_DRAWORDERSTEP
			float lowerBound();
			/// Higher drawpriority bound.
			// If CollectionNode is the last node on the main rendering list, there is no bound.
			// if there is other node after this, the bound is the next node's lowerBound or m_draworder-MIN_DRAWORDERSTEP
			float higherBound();

			/// is CollectionNode created for singleshot rendering?
			virtual const bool isSingleshot() const;

			/// Collections #4
			virtual const bool isCollection() const;
			// renderable type that the collection processes.
			virtual const Collection collectionType() const =0;

			/// applies single read-write Renderable into the collection.
			// pre-condition: Renderable *must not* have been previously fetched into any collection,
			// thus Renderable must not yet returned from its create() or createSingleshot() function.
			virtual void fetchNode( Renderable * prim ) = 0;

			/// applies read-write nodes into the collection from main rendering list.	[begin, end)
			// pre-condition: range must only contain same collectionType() nodes.
			// post-condition: iterators between [begin, end) are invalidated.
			virtual void fetchNodes( renderinglist_it_t begin, renderinglist_it_t end ) = 0;

			/// Converting write-once collection into read-write. Results in a collection that has
			/// nodes with randoomly associated primitives. Draw priority however, is well defined.
			//virtual void convertToReadWrite() =0;

			/// converting to read-write collection into write-once, simply discards the nodes and
			/// loads the primitives into extreme fast continous memory.
			//virtual void convertToWriteOnce() =0;

			/// Returns the sub-rendering list of Renderables.
			renderinglist_t & getNodes();

			/// removes single Renderable from collection.
			// post-condition: Renderable's attribute storgate IS NOT REMAPPED!
			// Renderable's target will remain pointing into the collection!
			// Caller must either destroy() or remapStrotgate() the Renderable before .
			virtual void detachNode( Renderable * prim) =0;

			/// By locking CollectionNode makes its contents static: singleshot drawings
			/// are not flushed at processRender(), and new data is not processed at all in processTransfer().
			/// CollectionNode usualy loads primitives into GL_STATIC_DRAW VBO(s) or into display list.
			virtual void lockTransfer(bool enable) =0;

		protected:
			CollectionNode();
			~CollectionNode();

			bool m_singleshot;
			mutable bool m_is_avgprorityvalid;
			renderinglist_t m_collectionlist;

			void destroy_list();

			// Counts number of nodes in range, recrusing into range's CollectionNodes.
			size_t range_size( renderinglist_it_t it, const renderinglist_it_t end ) const;

			// append range [begin, end) into m_collectionlist. Range is partly-erased from the mainlist.
			// Range must not contain iterator to *this.
			// Collections in rage are invalidated and must be destroyed after append_range().
			// WRITES: range in mainlist that contains the invalidated collections. The collections must
			// be destroyed.
			void append_range( renderinglist_it_t & begin, renderinglist_it_t & end );
	};
};

#endif // COLLECTIONNODE_H_INCLUDED
